#include <Arduino.h>
#include <WiFi.h>
#include "PubSubClient.h"   ////A client library for MQTT messaging.
#include <string.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
#include <SPI.h>
#include "ota.h"

TFT_eSPI tft = TFT_eSPI();
#define RSET_WIFI_PIN 15
#define DONT_WIFI_PIN 2

/* 连接WIFI SSID和密码 */
#define WIFI_SSID         "425"
#define WIFI_PASSWD       "425425425"

/* 设备的三元组信息*/
#define PRODUCT_KEY       "a1rBIU5IB5d"
#define DEVICE_NAME       "littlecome"
#define DEVICE_SECRET     "82cb375971b81c6b09ffec4832bd690a"
#define REGION_ID         "cn-shanghai"

/* 线上环境域名和端口号，不需要改 */
#define MQTT_SERVER       PRODUCT_KEY".iot-as-mqtt."REGION_ID ".aliyuncs.com"
#define MQTT_PORT         1883
#define MQTT_USRNAME      DEVICE_NAME"&"PRODUCT_KEY

#define CLIENT_ID         "a1rBIU5IB5d.littlecome|securemode=2,signmethod=hmacsha256,timestamp=1710431036987|"
#define MQTT_PASSWD       "33167275bc7ca1cc75d5730b02c6952f1a515a930f20225c0a3f0ed40c9b6f44"

//宏定义订阅主题
#define ALINK_BODY_FORMAT         "{\"id\":\"littlecome\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":%s}"
#define ALINK_TOPIC_PROP_POST     "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"

const char* TOPIC = "/sys/a1rBIU5IB5d/littlecome/thing/service/property/set"; 
unsigned long lastMs = 0;

WiFiClient espClient;
PubSubClient  client(espClient);

bool lig=0,dl=1,ct=1;
uint8_t hert=0,sop2=0,b_tep=0,hum=0,tep=0;
uint16_t lux=0,mq2=0;
uint8_t mqtt_ok = 0,uartinit = 1;
//连接wifi
void wifiInit()
{
    WiFi.begin(WIFI_SSID,WIFI_PASSWD);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(1000);
        Serial.println("WiFi not Connect");
    }
    /*tft show*/
    tft.fillRect(0, 0, 128, 25, TFT_BLUE);
    tft.setCursor(5, 5);
    tft.print("WiFi:");
    tft.print(WiFi.SSID());
    tft.setCursor(4, 15);
    tft.print("IP:");
    tft.print(WiFi.localIP());


}

//mqtt连接
void mqttCheckConnect()
{
    while (!client.connected())
    {
        Serial.println("Connecting to MQTT Server ...");
        /*tft show*/
        tft.fillRect(0, 24, 128, 10, TFT_ORANGE);
        tft.setCursor(5, 25);
        tft.print("Connecting MQTT...");

        if(client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD))
        {
          Serial.println("MQTT Connected!");
          /*tft show*/
          tft.fillRect(0, 24, 128, 10, TFT_ORANGE);
          tft.setCursor(5, 25);
          tft.print("MQTT Connected!");
        }
        else{
           Serial.print("MQTT Connect err:");
            Serial.println(client.state());
            /*tft show*/
            tft.fillRect(0, 24, 128, 10, TFT_ORANGE);
            tft.setCursor(5, 25);
            tft.print("MQTT err:");
            tft.print(client.state());
            delay(5000);
          }
        
    }
}

//上传数据
void mqttIntervalPost()
{
    char param[200];
    char jsonBuf[800];
    
    //upload humidity
    //soil_data = 20.8;  
    sprintf(param, "{\"humidity\":%d}", hum);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(b){
    //   Serial.println("publish Humidity success"); 
    // }else{
    //   Serial.println("publish Humidity fail"); 
    // }

    // Upload temperature
    //tep = 40.7;
    sprintf(param, "{\"temperature\":%d}",tep);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }

    // Upload body_temp
    //b_tep = 30.7;
    sprintf(param, "{\"body_temp\":%d}",b_tep);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }

    // Upload SO2
    //sop2 = 30.7;
    sprintf(param, "{\"SO2\":%d}",sop2);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }

    // Upload light
    //lig = 1;
    sprintf(param, "{\"light\":%d}",lig);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }

    // Upload door_lock
    //dl = 1;
    sprintf(param, "{\"door_lock\":%d}",dl);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }

    // Upload curtain
    //ct = 1;
    sprintf(param, "{\"curtain\":%d}",ct);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    // if(c){
    //   Serial.println("publish Temperature success"); 
    // }else{
    //   Serial.println("publish Temperature fail"); 
    // }
    
}

//回调函数
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);   // 打印主题信息
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]); // 打印主题内容
  }
  Serial.println();

 DynamicJsonDocument doc(1024);  //创建了一个名为 doc 的动态 JSON 文档
 deserializeJson(doc, String((char *)payload));  //从一个名为 payload 的数据中解析 JSON 数据并将其填充到 doc 中

// DynamicJsonDocument params = doc["params"];

if(doc["params"].containsKey("light"))
{
  Serial.println("GOT light CMD");   if(doc["params"]["light"]==1){
    Serial2.print("a");
  }
  else{Serial2.print("b");
  }
}

if(doc["params"].containsKey("door_lock"))
{
  Serial.println("GOT door_lock CMD"); 
  if(doc["params"]["door_lock"]==1){
    Serial2.print("c");
  }
  else{Serial2.print("d");
  }
}

if(doc["params"].containsKey("curtain"))
{
  Serial.println("GOT curtain CMD"); 
  if(doc["params"]["curtain"]==1){
    Serial2.print("e");
  }
  else{Serial2.print("f");
  }
}

}

void tft_show_text(void){
  tft.fillRect(0, 34, 128, 94, TFT_LIGHTGREY);

  tft.setCursor(14, 39);
  tft.print("temp:");
  tft.setCursor(16, 52);
  tft.print("hum:");
  tft.setCursor(14, 65);
  tft.print("smog:");
  tft.setCursor(16, 78);
  tft.print("ill:");
  tft.setCursor(10, 91);
  tft.print("H_rate:");
  tft.setCursor(10, 104);
  tft.print("B_temp:");
  tft.setCursor(5, 117);
  tft.print("B_oxygen:");

  tft.setCursor(98, 39);
  tft.print("*C");
  tft.setCursor(98, 52);
  tft.print("%RH");
  tft.setCursor(98, 65);
  tft.print("mg/m3");
  tft.setCursor(98, 78);
  tft.print("Lux");
  tft.setCursor(98, 91);
  tft.print("/min");
  tft.setCursor(98, 104);
  tft.print("*C");
  tft.setCursor(98, 117);
  tft.print("%");

}

void tft_show_number(void){
  tft.fillRect(60, 39, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 39);
  tft.print(tep);
  tft.fillRect(60, 52, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 52);
  tft.print(hum);
  tft.fillRect(60, 65, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 65);
  tft.print(mq2);
  tft.fillRect(60, 78, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 78);
  tft.print(lux);
  tft.fillRect(60, 91, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 91);
  tft.print(hert);
  tft.fillRect(60, 104, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(60, 104);
  tft.print(b_tep);
  tft.fillRect(60, 117, 35, 10, TFT_LIGHTGREY);
  tft.setCursor(70, 117);
  tft.print(sop2);
}

//连接WIFI
void SmartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig...");
  WiFi.beginSmartConfig();
  tft.fillRect(0, 0, 128, 15, TFT_BLUE);
  tft.setCursor(5, 5);
  tft.print("WiFi:Config...");
  while (1)
  {
    Serial.print(".");
    delay(500); 
    
    if (WiFi.smartConfigDone())
    {
      Serial.println("\r\nSmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      /*tft show*/
    tft.fillRect(0, 0, 128, 25, TFT_BLUE);
    tft.setCursor(5, 5);
    tft.print("WiFi:");
    tft.print(WiFi.SSID());
    tft.setCursor(4, 15);
    tft.print("IP:");
    tft.print(WiFi.localIP());
      break;
    }
  }
}

//自动重连
bool AutoConfig()
{
    WiFi.begin("425","425425425");
    //如果觉得时间太长可改
    for (int i = 0; i < 20; i++)
    {
        int wstatus = WiFi.status();
        if (wstatus == WL_CONNECTED)
        {
	        Serial.println("WIFI SmartConfig Success");
	        Serial.printf("SSID:%s", WiFi.SSID().c_str());
	        Serial.print("LocalIP:");
	        Serial.print(WiFi.localIP());
          /*tft show*/
    tft.fillRect(0, 0, 128, 25, TFT_BLUE);
    tft.setCursor(5, 5);
    tft.print("WiFi:");
    tft.print(WiFi.SSID());
    tft.setCursor(4, 15);
    tft.print("IP:");
    tft.print(WiFi.localIP());
	        return true;
        }
        else
        {
	        Serial.print("WIFI AutoConfig Waiting......");
	        Serial.println(wstatus);
	        delay(1000);
        }
        
    }
    Serial.println("WIFI AutoConfig Faild!" );
    return false;
}

#define LENGTH 20
uint8_t len = 0;
uint8_t Save_Data[LENGTH]={0};

void setup()
{
  pinMode(RSET_WIFI_PIN, INPUT_PULLUP);
  pinMode(DONT_WIFI_PIN, INPUT_PULLUP);

  tft.init();
  tft.setRotation(0);
  tft.fillScreen(TFT_WHITE);

  /*上电屏幕初始化*/
  tft.setTextColor(TFT_BLACK);
  tft.fillRect(0, 0, 128, 15, TFT_BLUE);
  tft.setTextSize(1);
  tft.setCursor(5, 5);
  tft.print("wifi connecting...");
  wifiInit();
  if (digitalRead(DONT_WIFI_PIN) == 0)//不开wifi
  {
    mqtt_ok = 1;
    Serial2.begin(115200);
    tft.fillRect(0, 0, 128, 25, TFT_BLUE);
    tft.setCursor(5, 5);
    tft.print("WiFi:N/A");
  }else{//开wifi
    if(digitalRead(RSET_WIFI_PIN) == 0){//需要重连
        SmartConfig();
    }else{
      AutoConfig();
    }
  }
  Serial.begin(115200);
  
  //wifiInit();
  client.setServer(MQTT_SERVER, MQTT_PORT);   /* 连接MQTT服务器 */
  client.setCallback(callback);                 //设定回调方式，当ESP32收到订阅消息时会调用此方法

  tft_show_text();
}

long otaInterval = 0;
void loop()
{  
  if (client.connected()==1 && uartinit == 1){
    uartinit = 0;
    Serial2.begin(115200);
    mqtt_ok = 1;
   }
   //Serial.println(Serial2.available());
    if (mqtt_ok == 1 && Serial2.available()) { 
      len = 0;
      while (Serial2.available()) {
        Save_Data[len] = Serial2.read();
        len++;
      }
        tep = Save_Data[1];
        hum = Save_Data[2];
        lux = Save_Data[3]<<8|Save_Data[4];
        hert = Save_Data[5];
        sop2 = Save_Data[6];
        b_tep = Save_Data[7];
        mq2 = Save_Data[8]<<8|Save_Data[9];
        tft_show_number();

    Serial.printf("%d %d %d %d %d %d %d\r\n",tep,hum,lux,hert,sop2,b_tep,mq2);
    }
    if (millis() - otaInterval >= 60000) {
      //循环时间，不要少于1分钟(60000)，否则会失败
      otaInterval = millis();
      httpGetOTA();
    }
    if (millis() - lastMs >= 5000)//检查自上次执行后是否已经过了5秒钟
    {
        lastMs = millis();
        mqttCheckConnect(); 
        /* 上报 */
        mqttIntervalPost();
    }
   client.loop();
} 
